package com.such.kit.io.simple;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.such.kit.Callable;
import com.such.kit.easyparam.ParamMap;
import com.such.kit.io.bean.SqlIOConfig;
import com.such.kit.io.simple.support.IOSimple;
import com.such.kit.io.support.IOSource;
import com.such.kit.placeholder.PlaceholderCommons;
import com.such.kit.stream.StreamCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * [继承扩展于 {@link IOSimple}] 的 sql 类型 IO 工具类
 * SqlIOSimple 通过 {@link SqlIOConfig} 配置 IO 特性
 * </pre>
 * @see IOSimple
 */
public class SqlIOSimple extends IOSimple {

	public static final String FILE_TYPE_SQL = "sql";
	/** ARG_QUALIFIER：参数界定符 */
	public static final char ARG_QUALIFIER = '\'';
	/** SQL_QUALIFIER：sql 界定符 */
	public static final char SQL_QUALIFIER = ';';

	private SqlIOConfig config;

	/**
	 * @param config 配置
	 * @throws Exception
	 */
	public SqlIOSimple(SqlIOConfig config) throws Exception {
		super.charset = config.getCharset();
		this.config = config;
	}

	@Override
	public String getFileType() {
		return FILE_TYPE_SQL;
	}

	@Override
	public void input(IOSource ioSource, InputStream resourceIn) throws Exception {
		if (ValidateCommons.isNotEmpty(this.config)) {
			String ie = this.config.getInputExpression();

			ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(1024);
			boolean argQualifierClose = true;
			int ch = 0;
			try {
				// 开始解析数据
				while ((ch = resourceIn.read()) != -1) {
					byteArrayOut.write(ch);
					// 检查到参数界定符
					if (ch == ARG_QUALIFIER) {
						argQualifierClose = false;
					}
					if (ch == ARG_QUALIFIER && !argQualifierClose) {
						argQualifierClose = true;
					}
					// 获取到 sql 界定符且不在参数界定符中（argQualifierClose = true），则认为读取完 1 条 sql
					if (ch == SQL_QUALIFIER && argQualifierClose) {
						byte[] byteArray = byteArrayOut.toByteArray();
						String stringOut = new String(byteArray, super.charset);
						// 可以执行 sql 需要去掉最后的 ;
						String sql = stringOut.substring(0, stringOut.length() - 1);
						// 此处的处理与 DatabaseIOSource 产生了耦合，详细可参考 SqlIOConfig.inputExpression 的说明
						ioSource.doInput(ie, new ParamMap<String, Object>().putParam(ie, sql), false, new HashMap<String, Object>());
						// 重置变量
						byteArrayOut = new ByteArrayOutputStream(1024);
					}
				}
				ioSource.doInput(null, null, true, null);
			} finally {
				StreamCommons.close(resourceIn);
				StreamCommons.close(byteArrayOut);
			}
		}
	}

	@Override
	public void output(IOSource ioSource, OutputStream resourceOut) throws Exception {
		if (ValidateCommons.isNotEmpty(this.config)) {
			String oe = this.config.getOutputExpression();
			ioSource.doOutput(oe, super.args, new OutputCallable(resourceOut));
		}
	}

	private class OutputCallable implements Callable<Map<String, Object>, Boolean> {

		private OutputStream out;

		public OutputCallable(OutputStream out) {
			this.out = out;
		}

		@Override
		public Boolean call(Map<String, Object> param) throws Exception {
			List<String> sqlTemplate = config.getSqlTemplate();

			for (String st : sqlTemplate) {
				String sqlResource = PlaceholderCommons.replacePlaceholder(st, param);
				this.out.write(sqlResource.getBytes(charset));
				this.out.write(SQL_QUALIFIER);
				this.out.write(StringCommons.NEW_LINE.getBytes());
			}
			return true;
		}

	}

}
